package cn.walls1717.leetcode.array;

/**
 * 704.二分查找
 * 力扣地址：https://leetcode-cn.com/problems/binary-search/
 *
 * @author walls1717
 * @since 2022-04-29
 **/
public class T704 {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4};
        int target = 4;
        System.out.println(binarySearch2(arr, target));
    }

    /**
     * 左闭右闭方案 [l,r]
     * @param nums 数组
     * @param target 目标值
     * @return 目标值下标，没有找到-1
     */
    private static int binarySearch(int[] nums, int target) {
        // 左值
        int l = 0;
        // 右值
        int r = nums.length - 1;
        // 中间值
        int m;
        // 因为是查询已经排序后的数组
        // 那么如果目标值比数组元素的第一个值还要小，或目标值比数组最后一个值还要大
        // 那证明数组中没有次元素，直接返回-1，减少循环次数
        if (nums[0] > target || nums[r] < target) {
            return -1;
        }
        while (l <= r) {
            // 使用位运算可以防止整数溢出，也可以提高效率
            m = l + ((r - l) >> 1);
            if (nums[m] == target) {
                return m;
            } else if (nums[m] < target) {
                // 如果中间值比目标值小，那就需要在中间值左边找
                l = m + 1;
            } else {
                r = m - 1;
            }
        }
        return -1;
    }

    /**
     * 左闭右开方案 [l,r)
     * @param nums 数组
     * @param target 目标值
     * @return 目标值下标，没有找到-1
     */
    private static int binarySearch2(int[] nums, int target) {
        int l = 0;
        int r = nums.length;
        int m;
        if (nums[0] > target || nums[r - 1] < target) {
            return -1;
        }
        // 与左闭右闭方案相同，只是这里不需要再判断 l == r了
        // 因为r取的是nums.length
        while (l < r) {
            m = l + ((r - l) >> 1);
            if (nums[m] == target) {
                return m;
            } else if(nums[m] < target){
                l = m + 1;
            } else {
                r = m - 1;
            }
        }
        return -1;
    }
}
